using System;
using System.Collections.Specialized;
using System.Security.Permissions;
using System.Web;
using Activa.CoolStorage;
using CodeStory.Core.ObjectEntity;

namespace CodeStory.Core.Providers
{
	[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
	public class CodeStorySiteMapProvider : StaticSiteMapProvider,IRefreshable
	{
		private SiteMapNode rootNode = null;

		// Implement a default constructor.
		public CodeStorySiteMapProvider() {
		}

		// Some basic state to help track the initialization state of the provider.
		private bool initialized = false;
		public virtual bool IsInitialized {
			get { return initialized; }
		}
		// Return the root node of the current site map.
		public override SiteMapNode RootNode {
			get {
				SiteMapNode temp = null;
				temp = BuildSiteMap();
				return temp;
			}
		}

		protected override SiteMapNode GetRootNodeCore() {
			return RootNode;
		}

		// Initialize is used to initialize the properties and any state that the
		// AccessProvider holds, but is not used to build the site map.
		// The site map is built when the BuildSiteMap method is called.
		public override void Initialize(string name, NameValueCollection attributes) {
			if (IsInitialized) {
				return;
			}
			base.Initialize(name, attributes);
			initialized = true;
		}

		///
		/// SiteMapProvider and StaticSiteMapProvider methods that this derived class must override.
		///
		// Clean up any collections or other state that an instance of this may hold.
		protected override void Clear() {
			lock (this) {
				rootNode = null;
				base.Clear();
			}
		}

		// Build an in-memory representation from persistent
		// storage, and return the root node of the site map.
		public override SiteMapNode BuildSiteMap() {
			if (rootNode != null && IsInitialized) {
				return rootNode;
			}
			// Since the SiteMap class is static, make sure that it is
			// not modified while the site map is built.
			lock (this) {
				Clear();
				if (! IsInitialized) {
					throw new Exception("BuildSiteMap called incorrectly.");
				}
				// If there is no root node, then there is no site map.
				if (null == rootNode) {
					rootNode = new SiteMapNode(this, "", string.Empty, "ROOT", string.Empty);
					BuildSiteMapInternal(rootNode, string.Empty);
				}
				return rootNode;
			}
		}

		private void BuildSiteMapInternal(SiteMapNode root, string parentKey) {
			CSList<SiteMapObject> list = SiteMapObject.List("ParentNodeKey=@ParentNodeKey", "@ParentNodeKey", parentKey);
			foreach (SiteMapObject si in list) {
				SiteMapNode child = new SiteMapNode(this, si.NodeKey, si.Url, si.Title, si.Description);
				AddNode(child, root);
				BuildSiteMapInternal(child, si.NodeKey);
			}
		}

		#region IRefreshable Members

		/// <summary>
		/// Refresh the state of the cached object.
		/// </summary>
		public void Refresh() {
			rootNode = null;
			Clear();
		}

		/// <summary>
		/// Refresh the state of the cached object.
		/// </summary>
		void IRefreshable.Refresh() {
			Refresh();
		}

		#endregion
	}
}